home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
strategy
/
shanghai.000
/
shanghai
/
shanghai-1.0
/
board.c
next >
Wrap
C/C++ Source or Header
|
1995-05-29
|
21KB
|
643 lines
#include <memory.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include "board.h"
#include "forms.h"
#include "game.h"
#include "gui.h"
#include "mapdata.h"
#include "shanghai.h"
static XColor icon_colors[16];
static GC gc_mask;
static GC gc_tile;
static GC gc_copy;
static Pixmap scrap;
static Pixmap icons;
static Pixmap mask;
static Pixmap shadow_top;
static Pixmap shadow_right;
static Pixmap status_pixmap;
static Pixmap status_mask;
static FL_RAW_CALLBACK rawcallback;
#ifndef __GNUC__
int intersect(int x1,int y1,int w1,int h1,
int x2,int y2,int w2,int h2,
int *x3,int *y3,int *w3,int *h3)
{
*x3 = max(x1,x2);
*y3 = max(y1,y2);
*w3 = min(x1+w1-1,x2+w2-1) - *x3 + 1;
*h3 = min(y1+h1-1,y2+h2-1) - *y3 + 1;
return((*w3 > 0) && (*h3 > 0));
}
#endif
static void initialize_colors(void)
{
int vmode;
int depth;
Display *disp;
Colormap colormap;
int col;
vmode = fl_get_vclass();
depth = fl_state[vmode].depth;
disp = fl_get_display();
colormap = fl_state[vmode].colormap;
for (col = 0; col < 16; col++)
if (!XAllocNamedColor(disp,colormap,
(depth < 4 ? mono_col_names :
depth== 4 ? simple_col_names : col_names)[col],
icon_colors+col,icon_colors+col)) {
fprintf(stderr,"Could not allocate color \"%s\"\n",
col_names[col]);
exit(1); }
return;
}
static void initialize_gc(void)
{
Display *disp;
int screen;
Window win;
disp = fl_get_display();
screen = fl_screen;
win = RootWindow(disp,screen);
gc_mask = XCreateGC(disp,win,0,NULL);
XSetGraphicsExposures(disp,gc_mask,False);
XSetForeground(disp,gc_mask,0);
XSetBackground(disp,gc_mask,~0);
XSetFunction(disp,gc_mask,GXand);
gc_tile = XCreateGC(disp,win,0,NULL);
XSetGraphicsExposures(disp,gc_tile,False);
XSetForeground(disp,gc_tile,icon_colors[15].pixel);
XSetBackground(disp,gc_tile,0);
XSetFunction(disp,gc_tile,GXor);
gc_copy = XCreateGC(disp,win,0,NULL);
XSetFunction(disp,gc_copy,GXcopy);
XSetForeground(disp,gc_copy,fl_get_flcolor(FL_COL1));
XSetBackground(disp,gc_copy,BlackPixel(disp,screen));
return;
}
static Pixmap convert_pixmap(int isselectable,unsigned char *data,
int width,int height,int *col_conv,
int *dither)
{
int vmode;
int depth;
Display *disp;
int screen;
Window win;
GC gc;
Pixmap bitmap,dest;
unsigned long pixel;
unsigned char *plane_bits,*sptr,*dptr,dithermask[4];
int col,hcol,rep,x,y,bit;
vmode = fl_get_vclass();
depth = fl_state[vmode].depth;
disp = fl_get_display();
screen = fl_screen;
win = RootWindow(disp,screen);
if ((plane_bits = malloc((((width+7)&~7)*height)/8)) == NULL) {
fprintf(stderr,"Out of memory\n");
exit(1); }
if ((dest = XCreatePixmap(disp,win,width,
isselectable?2*height:height,depth)) == 0) {
fprintf(stderr,"Could not allocate icon pixmap\n");
exit(1); }
gc = XCreateGC(disp,win,0,NULL);
XSetGraphicsExposures(disp,gc,False);
XSetForeground(disp,gc,0);
XSetBackground(disp,gc,0);
XFillRectangle(disp,dest,gc,0,0,width,isselectable?2*height:height);
XSetFunction(disp,gc,GXor);
memset(dithermask,0xFF,sizeof(dithermask));
for (col = 1; (hcol = col*16), col < 16; col++) {
if (dither) {
memset(dithermask,0,sizeof(dithermask));
for (x = 0; x < 16; x++)
if (col != 7 && dither[x] <= luminance[(8+col%8)|1])
dithermask[x/4] |= (0x01 << (x%4)) | (0x10 << (x%4)); }
for (rep = dither ? 1 : 0; rep >= 0; rep--) {
memset(plane_bits,0,(((width+7)&~7)*height)/8);
for (sptr = data, dptr = plane_bits, y=0; y < height; y++) {
for (x = 0, bit = 0x1; x < width; x += 2) {
if ((*sptr & 0xF0) == hcol)
*dptr |= bit;
bit <<= 1;
if ((*sptr++ & 0x0F) == col)
*dptr |= bit;
if ((bit <<= 1) == 0x100) {
*dptr++ &= dithermask[y%4];
bit = 0x1; } }
if (bit != 0x1)
*dptr++ &= dithermask[y%4]; }
if ((bitmap = XCreateBitmapFromData(disp,win,plane_bits,
width,height)) == 0) {
fprintf(stderr,"Out of server memory\n");
exit(1); }
pixel = icon_colors[col_conv[col]].pixel;
if (rep)
pixel = pixel == icon_colors[0].pixel ?
icon_colors[15].pixel : icon_colors[0].pixel;
XSetForeground(disp,gc,pixel);
XCopyPlane(disp,bitmap,dest,gc,0,0,width,height,0,0,1);
if (isselectable) {
if (depth >= 4) {
if (col == 7 || col == 8)
XSetForeground(disp,gc,icon_colors[col == 7 ? 8 : 7].pixel); }
else {
pixel = pixel == icon_colors[0].pixel ?
icon_colors[15].pixel : icon_colors[0].pixel;
XSetForeground(disp,gc,pixel); }
XCopyPlane(disp,bitmap,dest,gc,0,0,width,height,0,height,1); }
XFreePixmap(disp,bitmap);
if (rep)
for (x = 4; x--;) dithermask[x] ^= 0xFF; } }
XFreeGC(disp,gc);
free(plane_bits);
return(dest);
}
static void initialize_pixmap(void)
{
int vmode;
int depth;
Display *disp;
int screen;
Window win;
vmode = fl_get_vclass();
depth = fl_state[vmode].depth;
disp = fl_get_display();
screen = fl_screen;
win = RootWindow(disp,screen);
if ((scrap = XCreatePixmap(disp,win,
(ICON_WIDTH-DIM3DX-1)*15+DIM3DX+SHADOWX+1,
(ICON_HEIGHT-DIM3DY-1)*8+DIM3DY+SHADOWY+1,
depth)) == 0) {
fprintf(stderr,"Could not allocate scrap pixmap\n");
exit(1); }
icons = convert_pixmap(1,icons_data,ICON_WIDTH*ICON_COUNT,ICON_HEIGHT,
no_col_conv,depth < 4 ? dither_matrix : NULL);
status_pixmap = convert_pixmap(0,status_data,STATUS_WIDTH,
STATUS_HEIGHT*STATUS_COUNT,
depth < 4 ? status_col_conv : no_col_conv,
NULL);
if ((mask = XCreateBitmapFromData(disp,win,mask_bits,ICON_WIDTH,
ICON_HEIGHT)) == 0) {
fprintf(stderr,"Out of server memory\n");
exit(1); }
if ((status_mask = XCreateBitmapFromData(disp,win,status_mask_bits,
STATUS_WIDTH,
STATUS_HEIGHT*STATUS_COUNT)) == 0) {
fprintf(stderr,"Out of server memory\n");
exit(1); }
if ((shadow_top = XCreateBitmapFromData(disp,win,top_bits,TOP_WIDTHS,
TOP_HEIGHTS)) == 0) {
fprintf(stderr,"Out of server memory\n");
exit(1); }
if ((shadow_right = XCreateBitmapFromData(disp,win,right_bits,RIGHT_WIDTHS,
RIGHT_HEIGHTS)) == 0) {
fprintf(stderr,"Out of server memory\n");
exit(1); }
return;
}
static void initialize_board(void)
{
static int initialized = 0;
if (initialized)
return;
initialized = 1;
initialize_colors();
initialize_gc();
initialize_pixmap();
return;
}
#ifndef __GNUC__
void tile_pos(int pos,int *x,int *y,int *w,int *h,
int *ox,int *oy,int *ow,int *oh)
{
int ix,iy;
ix = (board[pos].x*(ICON_WIDTH-DIM3DX-1))/2 + DIM3DX*board[pos].depth;
iy = (board[pos].y*(ICON_HEIGHT-DIM3DY-1))/2 - DIM3DY*board[pos].depth;
if ( x) *x = ix+DIM3DX;
if ( y) *y = iy+SHADOWY;
if ( w) *w = ICON_WIDTH-DIM3DX;
if ( h) *h = ICON_HEIGHT-DIM3DY;
if (ox) *ox = ix;
if (oy) *oy = iy;
if (ow) *ow = ICON_WIDTH+SHADOWX;
if (oh) *oh = ICON_HEIGHT+SHADOWY;
return;
}
#endif
static void draw_tile(Display *disp,Drawable dst,int pos,int selected,
unsigned char *occ)
{
int ix,iy,iw,ih,ox,oy,i,icon;
if ((icon = occ[pos]) == NIL)
return;
icon = ((icon < 4*(3*9+7)) ? icon/4 : icon - (4-1)*(3*9+7))*ICON_WIDTH;
tile_pos(pos,&ix,&iy,&iw,&ih,&ox,&oy,0,0);
if ((i = board[pos].shd0) == NIL || occ[i] == NIL) {
if ((i = board[pos].shd1) != NIL && occ[i] != NIL) {
XCopyPlane(disp,shadow_top,dst,gc_mask,ICSTOP,ix,oy,1);
XCopyPlane(disp,shadow_top,dst,gc_tile,ICSTOP,ix,oy,1); }
else {
XCopyPlane(disp,shadow_top,dst,gc_mask,ICTOP, ix,oy,1);
XCopyPlane(disp,shadow_top,dst,gc_tile,ICTOP, ix,oy,1); } }
if ((pos == 3 && occ[ 1] != NIL) ||
(pos == 143 && occ[140] == NIL && occ[141] != NIL)) {
XCopyPlane(disp,shadow_right,dst,gc_mask,ICHHIGH,ix+iw,oy+1,1);
XCopyPlane(disp,shadow_right,dst,gc_tile,ICHHIGH,ix+iw,oy+1,1); }
else if ((pos == 4 && occ[1] != NIL) ||
(pos == 143 && occ[140] != NIL && occ[141] == NIL)) {
XCopyPlane(disp,shadow_right,dst,gc_mask,ICHLOW,ix+iw,
iy+(ICON_HEIGHT-DIM3DY)/2+1,1);
XCopyPlane(disp,shadow_right,dst,gc_tile,ICHLOW,ix+iw,
iy+(ICON_HEIGHT-DIM3DY)/2+1,1);}
else if ((i = board[pos].right[0]) == NIL || occ[i] == NIL) {
if ((i = board[pos].shd1) != NIL && occ[i] != NIL) {
XCopyPlane(disp,shadow_right,dst,gc_mask,ICSRIGHT,ix+iw,oy+1,1);
XCopyPlane(disp,shadow_right,dst,gc_tile,ICSRIGHT,ix+iw,oy+1,1); }
else {
XCopyPlane(disp,shadow_right,dst,gc_mask,ICRIGHT,ix+iw,oy+1,1);
XCopyPlane(disp,shadow_right,dst,gc_tile,ICRIGHT,ix+iw,oy+1,1); } }
XCopyPlane(disp,mask,dst,gc_mask,0,0,ICON_WIDTH,ICON_HEIGHT,ox,iy,1);
XCopyArea(disp,icons,dst,gc_tile,icon,0,ICON_WIDTH,ICON_HEIGHT,ox,iy);
if (selected) {
XCopyPlane(disp,mask,dst,gc_mask,ix-ox+1,1,iw-2,ih-2,ix+1,iy+1,1);
XCopyArea(disp,icons,dst,gc_tile,icon+(ix-ox)+1,ICON_HEIGHT+1,
iw-2,ih-2,ix+1,iy+1); }
return;
}
void draw_area(int x,int y,int w,int h,BoardRec *board_rec)
{
Display *disp = board_rec->disp;
Drawable win = board_rec->win;
unsigned char *occ = board_rec->occ;
int i,j,ox,oy,ow,oh,ix,iy,iw,ih,depth = -1;
if (board_rec->paused)
return;
XFillRectangle(disp,scrap,gc_copy,x,y,w,h);
/* GNU C's inline optimization simplifies this code a lot! */
tile_pos(0,0,0,&iw,&ih,0,0,&ow,&oh);
if (w == iw && h == ih) for (i = 0; i < 144; i++) {
tile_pos(i,&ix,&iy,0,0,0,0,0,0);
if (x == ix && y == iy) { depth = board[i].depth; break; } }
else if (w == ow && h == oh) for (i = 0; i < 144; i++) {
tile_pos(i,0,0,0,0,&ox,&oy,0,0);
if (x == ox && y == oy) { depth = board[i].depth-1; break; } }
for (i = 0; i < 144; i++)
if (occ[i] != NIL &&
((j = board[i].top) == NIL || occ[j] == NIL ||
board[i].depth >= depth)) {
tile_pos(i,0,0,0,0,&ox,&oy,&ow,&oh);
if (intersect(x,y,w,h,ox,oy,ow,oh,&ox,&oy,&ow,&oh))
draw_tile(disp,scrap,i,i == board_rec->sel0 ||
i == board_rec->sel1 || board_rec->inverted[i] != NIL,occ); }
XCopyArea(disp,scrap,win,gc_copy,x,y,w,h,board_rec->ox+x,board_rec->oy+y);
return;
}
void draw_all_tiles(BoardRec *board_rec)
{
FL_OBJECT * const board_frame = board_rec->board->board_frame;
FL_OBJECT * const status_box = board_rec->board->status_box;
/* this is a dirty hack, but prevents flicker */
draw_area(0,0,status_box->x-board_frame->x,board_frame->h,board_rec);
draw_area(status_box->x-board_frame->x,
status_box->y+status_box->h-board_frame->y,
board_frame->x+board_frame->w-status_box->x,
board_frame->y+board_frame->h-status_box->y-status_box->h,
board_rec);
return;
}
static int focus_out(FL_FORM *board,void *ev)
{
/* XForms does not support tracking of focus, so we will only get
LeaveNotify events; besides, it it often hard to differentiate
between leaving the main window and leaving popup menus;
this code fails to detect focus changes that are not accompanied
by moving the pointer out of the main window!
hopefully this will be fixed some day */
BoardRec * const board_rec = board->u_vdata;
XEvent * const event = ev;
int xr,yr,x,y;
unsigned int mask;
Window root,child = None;
if (event->type == FocusOut ||
(event->type == LeaveNotify &&
((event->xcrossing.mode == NotifyNormal &&
(event->xcrossing.detail == NotifyNonlinear ||
event->xcrossing.detail == NotifyAncestor) &&
(event->xcrossing.x < 0 || event->xcrossing.x >= board->w ||
event->xcrossing.y < 0 || event->xcrossing.y >= board->h)) ||
!XQueryPointer(board_rec->disp,board_rec->win,&root,&child,
&xr,&yr,&x,&y,&mask) ||
x < 0 || x >= board->w || y < 0 || y >= board->h))) {
if (board_rec->time > 0) {
board_rec->paused = 1;
fl_show_object(board_rec->board->pausebox);
if ((board_rec->time -= time(0)) == 0)
board_rec->time = -1;
update_info_box(board_rec); } }
return(0);
}
static __inline__ long long timediff(struct timeval *tv1,struct timeval *tv2)
{
return(tv1->tv_usec - tv2->tv_usec + (tv1->tv_sec-tv2->tv_sec)*1000000LL);
}
static void handle_step(BoardRec *board_rec)
{
static long long const limit1 = 150000;
static long long loops = 1;
long long i,l;
struct timeval tv1,tv2;
int j;
for (j = 10; j--;) {
gettimeofday(&tv1,NULL);
if (board_rec->time > 0 && timediff(&tv1,&board_rec->tv) > 200000) {
update_info_box(board_rec);
gettimeofday(&board_rec->tv,NULL); }
for (i = loops; i--;)
if (depth_scan(board_rec) != dsBusy)
return;
gettimeofday(&tv2,NULL);
if ((l = timediff(&tv2,&tv1)) <= 0 ||
(l = (loops*limit1)/l) <= 0) loops = 1;
else if (l > loops)
if (10*l > 11*loops) loops = (11*(loops+1))/10; else loops = l;
else loops = l;
if (XPending(board_rec->disp))
break; }
return;
}
static int board_handle_free(FL_OBJECT *ob,int event,FL_Coord mx,FL_Coord my,
int key,void *xev)
{
BoardRec *board_rec = (BoardRec *)ob->u_vdata;
if (event == FL_DRAW || event == FL_PUSH || event == FL_STEP) {
if (board_rec->disp == NULL) {
board_rec->disp = fl_get_display();
board_rec->win = FL_ObjWin(ob);
initialize_board(); } }
switch (event) {
case FL_DRAW:
if (!board_rec->paused)
draw_area(0,0,ob->w,ob->h,board_rec);
break;
case FL_PUSH:
if (!board_rec->paused)
handle_mouse_push(mx - ob->x,my - ob->y,key,board_rec);
break;
case FL_STEP:
handle_step(board_rec);
default:
break; }
return(0);
}
void board_callback(FL_OBJECT *ob,long data)
{
FD_board * const fd_board = (FD_board *)data;
FL_OBJECT * const board_frame = fd_board->board_frame;
XEvent *event;
event = (XEvent *)fl_last_event();
if (event->type == ButtonPress)
board_handle_free(board_frame,FL_PUSH,event->xbutton.x,event->xbutton.y,
event->xbutton.button,event);
return;
}
static int lsprintf(FL_OBJECT *ob,const char *s,...)
__attribute__((format(printf,2,3)));
static int lsprintf(FL_OBJECT *ob,const char *s,...)
{
static char buffer[80];
va_list arg;
int rc;
va_start(arg,s);
rc = vsprintf(buffer,s,arg);
fl_set_object_label(ob,buffer);
va_end(arg);
return(rc);
}
void update_info_box(BoardRec *board_rec)
{
InfoBoxRec infobox_rec;
time_t secs;
infobox_rec.seed = board_rec->seed;
infobox_rec.remain = board_rec->remain;
infobox_rec.matchcount = board_rec->matchcount;
secs = board_rec->time > 0 ? time(0) - board_rec->time :
board_rec->time < 0 ? - board_rec->time : 0;
if (secs < 3600) {
infobox_rec.time0 = (int)(secs/60);
infobox_rec.time1 = 0;
infobox_rec.time2 = (int)(secs%60); }
else if (secs < 360000) {
infobox_rec.time0 = (int)(secs/3600);
infobox_rec.time1 = 1;
infobox_rec.time2 = (int)(secs%3600)/60; }
else {
infobox_rec.time0 = 0;
infobox_rec.time1 = 2;
infobox_rec.time2 = 0; }
infobox_rec.rank = board_rec->rank;
infobox_rec.scoremode = board_rec->scoremode;
infobox_rec.status = board_rec->depthscan.status;
if (memcmp(&infobox_rec,&board_rec->infobox,sizeof(InfoBoxRec))) {
fl_freeze_form(board_rec->board->board);
if (!board_rec->paused) {
if (infobox_rec.seed != board_rec->infobox.seed) {
char buffer[12];
sprintf(buffer,"%09d",infobox_rec.seed);
fl_set_input(board_rec->board->inp_board_num,buffer); }
if (infobox_rec.remain != board_rec->infobox.remain)
lsprintf(board_rec->board->remain,"Remain: %d",infobox_rec.remain);
if (infobox_rec.matchcount != board_rec->infobox.matchcount)
lsprintf(board_rec->board->match,"Match: %d",infobox_rec.matchcount);
if (infobox_rec.time0 != board_rec->infobox.time0 ||
infobox_rec.time1 != board_rec->infobox.time1 ||
infobox_rec.time2 != board_rec->infobox.time2)
lsprintf(board_rec->board->time,infobox_rec.time1 == 2 ?
"Time ???" : "Time %2d%c%02d",infobox_rec.time0,
infobox_rec.time1?'h':':',infobox_rec.time2);
if (infobox_rec.rank != board_rec->infobox.rank)
lsprintf(board_rec->board->rank,infobox_rec.rank ?
"Rank #%d":"No rank",infobox_rec.rank);
if (infobox_rec.scoremode != board_rec->infobox.scoremode)
lsprintf(board_rec->board->scoremode,"%sScoring",
infobox_rec.scoremode?"":"Non-"); }
if (infobox_rec.status != board_rec->infobox.status)
fl_redraw_object(board_rec->board->status);
fl_unfreeze_form(board_rec->board->board);
if (board_rec->paused)
board_rec->infobox.status = infobox_rec.status;
else
board_rec->infobox = infobox_rec; }
fl_set_menu_item_mode(board_rec->board->file,2,board_rec->time == 0 ?
FL_PUP_GREY : FL_PUP_NONE);
fl_set_menu_item_mode(board_rec->board->options,1,infobox_rec.remain == 144 ?
FL_PUP_GREY : FL_PUP_NONE);
fl_set_menu_item_mode(board_rec->board->options,2,(!board_rec->time ||
!board_rec->matchcount ? FL_PUP_GREY : FL_PUP_NONE) |
(board_rec->paused ? FL_PUP_CHECK : FL_PUP_BOX));
fl_set_menu_item_mode(board_rec->board->options,3,board_rec->isfastgame ?
FL_PUP_CHECK : FL_PUP_BOX);
return;
}
static int status_handle_free(FL_OBJECT *ob,int event,FL_Coord mx,FL_Coord my,
int key,void *xev)
{
BoardRec *board_rec = (BoardRec *)ob->u_vdata;
if (event == FL_DRAW || event == FL_PUSH) {
if (board_rec->disp == NULL) {
board_rec->disp = fl_get_display();
board_rec->win = FL_ObjWin(ob);
initialize_board(); } }
switch (event) {
case FL_DRAW: {
Display * const disp = board_rec->disp;
Drawable const win = board_rec->win;
enum dsStatus status = board_rec->depthscan.status;
XFillRectangle(disp,win,gc_copy,ob->x,ob->y,ob->w,ob->h);
XCopyPlane(disp,status_mask,win,gc_mask,0,STATUS_HEIGHT*(status-dsBusy),
STATUS_WIDTH,STATUS_HEIGHT,ob->x,ob->y,1);
XCopyArea(disp,status_pixmap,win,gc_tile,0,STATUS_HEIGHT*(status-dsBusy),
STATUS_WIDTH,STATUS_HEIGHT,ob->x,ob->y);
break; }
case FL_PUSH:
if (!board_rec->paused)
handle_status_push(key,board_rec);
break;
default:
break; }
return(0);
}
void board_inp_board_num(FL_OBJECT *ob, long data)
{
FD_board *fd_board = (FD_board *)data;
BoardRec *board_rec = (BoardRec *)fd_board->board_frame->u_vdata;
if (board_rec->boardnumeditable)
deactivate_board_num(board_rec);
else {
board_rec->boardnumeditable = 1;
fl_activate_object(fd_board->inp_board_num);
fl_set_object_focus(fd_board->board,fd_board->inp_board_num); }
return;
}
void deactivate_board_num(BoardRec *board_rec)
{
int seed;
if (board_rec->boardnumeditable) {
board_rec->boardnumeditable = 0;
fl_deactivate_object(board_rec->board->inp_board_num);
fl_set_object_focus(board_rec->board->board,NULL);
seed = atoi(fl_get_input(board_rec->board->inp_board_num));
if (seed != board_rec->seed) {
FD_board *fd_board = board_rec->board;
default_isfastgame = board_rec->isfastgame;
if (!seed) {
free(board_rec); board_rec = NULL;
srand(time(0)); do {seed = rand();} while (seed == 0); }
board_rec = initialize_board_rec(fd_board,board_rec,seed);
draw_all_tiles(board_rec); } }
return;
}
static int board_close(FL_FORM *board,void *ptr)
{
free(board->u_vdata);
fl_hide_form(board);
fl_free_form(board);
if (--win_count == 0)
exit(0);
return(FL_IGNORE);
}
static void fl_xset_menu(FL_OBJECT *ob,char *m,...)
{
int i = 0;
va_list arg_ptr;
char *s;
fl_set_menu(ob,m);
for (va_start(arg_ptr,m); (s = va_arg(arg_ptr,char *)) != NULL; )
fl_set_menu_item_shortcut(ob,++i,s);
return;
}
FD_board *new_board(void)
{
FD_board *fd_board;
int seed;
srand(time(0)); do {seed = rand();} while (!seed);
fd_board = create_form_board();
fl_xset_menu(fd_board->shanghai,"About...","Aa#A#a",NULL);
fl_xset_menu(fd_board->file,"New Game|Restart%l|Open Window|Close%l|Quit",
"Nn#N#n","Rr#R#r","Oo#O#o","Cc#C#c","Qq#Q#q\x1B",NULL);
fl_xset_menu(fd_board->options,"Undo|Pause%l|Fast moves","Uu#U#u","Pp#P#p",
"Ff#F#f",NULL);
initialize_board_rec(fd_board,NULL,seed);
fd_board->board_frame->objclass = FL_FREE;
fd_board->board_frame->type = FL_CONTINUOUS_FREE;
fd_board->board_frame->boxtype = 0;
fd_board->board_frame->handle = board_handle_free;
fd_board->board_frame->active = 1;
fd_board->board_frame->automatic = 1;
fd_board->status->objclass = FL_FREE;
fd_board->status->type = FL_INPUT_FREE;
fd_board->status->boxtype = 0;
fd_board->status->handle = status_handle_free;
fd_board->status->active = 1;
fd_board->status->automatic = 0;
win_count++;
fl_set_form_atclose(fd_board->board,board_close,NULL);
fl_set_form_minsize(fd_board->board,fd_board->board->w,fd_board->board->h);
fl_set_form_maxsize(fd_board->board,fd_board->board->w,fd_board->board->h);
rawcallback = fl_register_raw_callback(fd_board->board,FL_ALL_EVENT,
focus_out);
fl_show_form(fd_board->board,FL_PLACE_FREE,FL_FULLBORDER,"Shanghai for X");
return(fd_board);
}